{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 回调和协程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [callback_vs_coroutine](./callback_hell/callback_vs_coroutine_sequential.cpp): https://godbolt.org/z/ThTxeacv4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "| 方案                          | 核心特征                                       | 优点                                                   | 缺点                                                         | 适用场景                                                     |\n",
    "| ----------------------------- | ---------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| **嵌套回调（callback hell）** | 每个异步步骤在前一步的回调中排队执行           | 不需要语言新特性；所有异步库都支持；实现最快           | 控制流被拆碎，嵌套层级深；局部状态难管理；错误处理繁琐；调试困难 | 简单异步流程；需兼容旧代码/旧编译器；快速原型                |\n",
    "| **显式状态机**                | 定义状态枚举，由一个回调驱动状态推进           | 控制流集中在 `advance()`；状态转移一目了然；性能利好   | 需要手工维护状态和转移表；代码量大；扩展步骤成本高于协程     | 协议实现、驱动程序等对状态控制要求严格的场景；对性能/内存敏感的低层模块 |\n",
    "| **C++20 协程**                | 使用 `co_await` 与协程帧，编译器生成隐式状态机 | 代码近似同步语义，易读易维护；异常处理自然；可组合性强 | 依赖 C++20/协程支持的编译器与标准库；对工具链和团队有学习门槛；调试需现代工具 | 复杂业务流程；需要高可维护性和可测试性的中大型项目；新的代码基 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "回调（Callback Hell）\n",
    "\n",
    "- **时代背景**：早期 C/C++ 网络/GUI 库（例如 ACE、libevent、Win32 API、Boost.Asio 旧接口）仅提供基于回调的异步模型。\n",
    "- **语言限制**：传统 C++ 没有协程或可移植的纤程实现，想表达“等待某事件再继续”只能靠回调。\n",
    "- **工程现实**：在需要快速迭代或无权升级编译器/标准库的旧项目中，回调是唯一可行解。\n",
    "\n",
    "显式状态机\n",
    "\n",
    "- **驱动需求**：通信协议、嵌入式设备、游戏服务器等需要明确列出状态和转移关系，以便审计和验证。\n",
    "- **通用模式**：FSM（Finite State Machine）是软件工程中经典手法，在 C++11 之前就广泛用于协议栈和事件驱动系统。\n",
    "- **演化路径**：很多团队为了摆脱“回调地狱”，会手动把流程抽象成状态机，以提升可读性和调试能力，兼顾性能。\n",
    "\n",
    "C++20 协程\n",
    "\n",
    "- **标准化进程**：2010 年后，C#、Python、JavaScript 已引入 async/await；C++ 社区也希望摆脱回调写法。2017 年 TS（Technical Specification）成熟，2020 年正式进入标准。\n",
    "- **库配套**：Boost.Asio、cppcoro、Folly 等现代库逐步提供协程接口，生态成熟。\n",
    "- **工程驱动**：随着编译器（GCC/Clang/MSVC）支持协程，企业为降低维护成本、提升可读性，逐渐迁移到协程写法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "迁移策略建议\n",
    "\n",
    "1. **遗留系统**：保留回调或显式状态机，逐步封装/隔离旧接口。\n",
    "2. **新项目**：优先选择协程接口，提升可维护性。\n",
    "3. **过渡期**：使用适配器同时提供回调与协程 API，平滑升级团队与工具链。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 适配器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "“适配器”（adapter）: 提供一个**统一的异步函数签名**，能够同时满足回调和协程两种调用方式。实现的关键，是让该函数接受一个**Completion Token**（完成策略），然后在内部把回调调用和协程调用统一处理。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 场景                             | 建议使用                                                     |\n",
    "| -------------------------------- | ------------------------------------------------------------ |\n",
    "| 想让新旧调用方共存、统一接口     | 优先使用 **正向适配**（Completion Token 模式）               |\n",
    "| 核心逻辑已协程化，但外部必须回调 | 使用 **反向适配**（`co_spawn` 包装成回调）                   |\n",
    "| 渐进式迁移整个系统               | 兼用两种适配器：先正向适配统一入口，再在某些模块内反向适配向外暴露 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 正向适配：一个接口同时支持回调和协程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[forward_adapter.cpp](./forward_adapter/forward_adapter.cpp), https://godbolt.org/z/rxfxhThsM"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**目标**\n",
    "- 让同一个异步函数既能被旧代码通过回调使用，又能被新代码 `co_await`。\n",
    "\n",
    "\n",
    "**做法**\n",
    "- 封装一个统一的 `async_...` 函数，参数表最后接受 **Completion Token**（例如回调、`use_future`、`use_awaitable`）。\n",
    "- 在函数内部使用 `asio::async_initiate`（或类似机制）来触发真正的异步操作。\n",
    "- 底层既可以继续调用旧回调库，也可以直接调用协程实现。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 反向适配：协程实现对外暴露回调接口"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[reverse_adapter.cpp](./reverse_adapter/reverse_adapter.cpp), https://godbolt.org/z/E5czT9GG7"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**目标**\n",
    "- 当核心逻辑已经使用协程编写，但外界（或第三方）仍依赖回调接口，需要提供“回调版包装”。\n",
    "\n",
    "**做法**\n",
    "\n",
    "- 使用 `co_spawn` 启动协程，协程执行完毕后调用回调。\n",
    "- 在协程内捕获异常并转换为 `error_code`，保证回调调用安全。\n",
    "- 使用 `asio::post` 或 `asio::dispatch` 让回调在正确的执行上下文中触发。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
